AWS IoTのDevice GatewayにHTTPプロトコルとクライアント認証でメッセージ送信する
AWS IoTのDevice Gatewayは通信プロトコルとしてはHTTPとMQTTに対応し、認証としてはAWS認証(IAMクレデンシャル、cognitoなど)とクライアント証明書に対応しています。
AWSのドキュメントでは
- MQTTプロトコルとクライアント認証
- HTTPプロトコルとAWS認証
を使ったサンプルをよく見かけ、これらの接続方法を紹介してきました。
- AWS IoT Message BrokerのMQTTでpub/subをやってみた #reinvent
- AWS IoT Device GatewayにHTTPでPublishしてみた #reinvent
実はHTTPプロトコルとクライアント認証の組み合わせも使えます。
そこで今回は Linux/Mac上のcurlからクライアント認証でAWS IoT Device Gatewayにメッセージ送信する方法を紹介します。
- AWS IoT Device Gatewayとクライアント認証を使った疎通確認をコマンドラインから行いたい
- 疎通確認のためだけにMQTTクライアントはインストールしたくなく、curlのようにデフォルトでインストールされているプログラムですませたい
ようなケースで有効かと思います。
認証の準備
X.509クライアント証明書で認証するために、iot create-keys-and-certificate
コマンドで新規に公開鍵のペアとX.509証明書を生成します。
$ aws iot create-keys-and-certificate \ --set-as-active \ --certificate-pem-outfile cert.pem \ --public-key-outfile publicKey.pem \ --private-key-outfile privateKey.pem { "certificateArn": "arn:aws:iot:ap-northeast-1:123456789012:cert/6e16483d95f1e66d70c532ac287aedb73c72a726c38bae6de3a427b583778bdc", "certificatePem": "-----BEGIN CERTIFICATE-----\nMI...g==\n-----END CERTIFICATE-----\n", "keyPair": { "PublicKey": "-----BEGIN PUBLIC KEY-----\nMIIB...QAB\n-----END PUBLIC KEY-----\n", "PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\nMII...xDw==\n-----END RSA PRIVATE KEY-----\n" }, "certificateId": "6e16483d95f1e66d70c532ac287aedb73c72a726c38bae6de3a427b583778bdc" }
オプション | 説明 |
--certificate-pem-outfile | 証明書を保存するパス |
--public-key-outfile | 公開鍵を保存するパス |
--private-key-outfile | プライベート鍵を保存するパス |
また、ルート CA もシマンテックサイトから取得します。
$ curl -o rootCA.pem -s https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem
AWS IoTポリシーの設定
AWS IoTの権限管理をするポリシーを作成します。
今回はDevice GatewayへのPublish
のみを許可します。
$ cat iot-policy.json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Publish" ], "Resource": [ "*" ] } ] } $ aws iot create-policy --policy-name "IoTPubSub" --policy-document file://iot-policy.json { "policyName": "IoTPubSub", "policyArn": "arn:aws:iot:ap-northeast-1:123456789012:policy/IoTPubSub", "policyDocument": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Action\": [\n \"iot:Publish\"\n ],\n \"Resource\": [\n \"*\"\n ]\n }\n ]\n}\n", "policyVersionId": "1" } $ aws iot list-policies { "policies": [ { "policyName": "IoTPubSub", "policyArn": "arn:aws:iot:ap-northeast-1:123456789012:policy/IoTPubSub" } ] }
作成したAWS IoTポリシーを証明書に紐付けます。 プリンシパルとなるのはaws iot create-keys-and-certificate
コマンドを実行した時の certificateArn
です。
$ aws iot attach-principal-policy \ --principal "arn:aws:iot:ap-northeast-1:123456789012:cert/6e16483d95f1e66d70c532ac287aedb73c72a726c38bae6de3a427b583778bdc" \ --policy-name "IoTPubSub" $ aws iot list-principal-policies --principal "arn:aws:iot:ap-northeast-1:123456789012:cert/6e16483d95f1e66d70c532ac287aedb73c72a726c38bae6de3a427b583778bdc" { "policies": [ { "policyName": "IoTPubSub", "policyArn": "arn:aws:iot:ap-northeast-1:123456789012:policy/IoTPubSub" } ] }
メッセージ送信
ここまでで準備が整いました。
最後に
- Amazon Linux
- Mac
それぞれから curl を使ってメッセージ送信します。
エンドポイントの確認
次のコマンドでDevice Gatewayのエンドポイントを確認します。 このエンドポイントは AWS アカウントごとに存在します。
$ aws iot describe-endpoint { "endpointAddress": "DUMMY.iot.ap-northeast-1.amazonaws.com" }
URL は次のような形をしています。
https://ENDPOINT_ADDRESS:8443/topics/PATH/TO/TOPIC?qos=LEVEL
iot describe-endpoint
を実行したendpointAddress
がDUMMY.iot.ap-northeast-1.amazonaws.com
- メッセージ送信するトピックが
foo/bar
- MQTTのサブスクライバー向けQoSが
1
であれば
https://DUMMY.iot.ap-northeast-1.amazonaws.com:8443/topics/foo/bar?qos=1
となります。
HTTPSリクエスト時のポートは 8443 です。MQTTS向けの8883ではありませんので注意してください。
送信メッセージをPOST
で渡します。
Amazon Linux版
Amazon Linuxのcurlからは次のコマンドでメッセージ送信します。
$ curl -D - \ --tlsv1.2 \ -X POST \ --cert ./cert.pem \ --key ./privateKey.pem \ --cacert ./rootCA.pem \ https://DUMMY.iot.ap-northeast-1.amazonaws.com:8443/topics/test?qos=0 \ -d @payload.json HTTP/1.1 200 OK content-type: application/json content-length: 2 date: Sat, 23 Jan 2016 04:37:34 GMT x-amzn-RequestId: e12424c2-1272-404b-b62b-1afbc8803358 connection: Keep-Alive OK
オプション | 説明 |
--tls1.2 | AWS IoTのHTTP版Device GatewayはTLS1.2のみに対応しているため、明示的に指定します |
--cert | 証明書のパスです |
--key | プライベート鍵のパスです |
--cacert | ルート証明書のパスです |
-d | POSTするペイロードのパスを@で指定します |
注意点としては、ファイルがカレントディレクトリにある場合、NSS証明書のニックネームとの衝突を避けるために、パスを./
で始めるようにしてください。
Mac版
Macのcurlから Amazon Linux版と同じコマンドを実行すると
$ curl -D - \ --tlsv1.2 \ -X POST \ --cert ./cert.pem \ --key ./privateKey.pem \ --cacert ./rootCA.pem \ https://DUMMY.iot.ap-northeast-1.amazonaws.com:8443/topics/test?qos=0 \ -d @payload.json curl: (58) SSL: Can't load the certificate "./cert.pem" and its private key: OSStatus -25299
というエラーが発生します。
Mac版curlはSSL通信ライブラリにOpenSSLではなくSecureTransportが使われているのが原因です。
$ curl --version
を実行して確認して見ましょう。
$ curl --version curl 7.43.0 (x86_64-apple-darwin14.0) libcurl/7.43.0 SecureTransport zlib/1.2.5 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz UnixSockets
解決策は次のページに記載されています。
Important note for curl users on OS X Yosemite 10.10
何通りか存在しますが、今回は2bの解決策、つまり、-E/--cert
オプションに証明書とプライベート鍵を含んだPKCS#12形式のファイルを指定します。
まずopensslコマンドで証明書とプライベート鍵をPKCS#12形式に変換します。
$ openssl pkcs12 -export -clcerts -in cert.pem -inkey privateKey.pem -out cert.p12 Enter Export Password: Verifying - Enter Export Password:
次に -E/--cert
オプションに作成したPKCS#12形式のファイルのパスとパスワードを -E ./PATH/TO/PKCS_12_ENCODED_FILE:YOUR_PASSWORD
の形式で指定します。
$ curl -D - --tlsv1.2 \ -X POST \ -E ./cert.p12:YOUR_PASSWORD \ --cacert ./rootCA.pem \ https://DUMMY.iot.ap-northeast-1.amazonaws.com:8443/topics/test\?qos\=0 \ -d @payload.json HTTP/1.1 200 OK content-type: application/json content-length: 2 date: Sat, 23 Jan 2016 04:55:29 GMT x-amzn-RequestId: b4c843fa-2b25-4423-b154-e3efaef22d1d connection: Keep-Alive OK
メッセージ送信に成功しました。
参照
- AWS IoTメッセージブローカーのプロトコルについて http://docs.aws.amazon.com/iot/latest/developerguide/protocols.html
- curlからAWS IoTメッセージブローカーへのクライアント認証のコマンド例 https://github.com/aws/aws-iot-device-sdk-embedded-C/issues/7#issuecomment-171749256
- curl とMacについてhttp://curl.haxx.se/mail/archive-2014-10/0053.html